package com.frank.javaBeanValidation.config;

import com.alibaba.fastjson.JSON;
import com.frank.javaBeanValidation.entity.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
 * @author 小石潭记
 * @date 2020/10/28 14:27
 * @Description: @Validated：支持分组
 *                          可以用在类型、方法和方法参数上。但是不能用在成员属性（字段）上
 *               @Valid：    不支持分组
 *                          可以用在方法、构造函数、方法参数和成员属性（字段）上
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class);

    /**
     * 统一异常处理
     * @param exceptionResolvers
     */
    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
        exceptionResolvers.add((request, response, handler, e) -> {
            Result result = new Result();
            // 异常处理
            // 参数异常判断
            // 参数异常判断
            if (e instanceof BindingResult || e instanceof MethodArgumentNotValidException) {
                StringBuilder errorMessage = new StringBuilder();
                List<ObjectError> allErrors;
                if (e instanceof BindingResult) {
                    allErrors = ((BindingResult) e).getAllErrors();
                } else {
                    BindingResult bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();
                    allErrors = bindingResult.getAllErrors();
                }
                for (int i = 0; i < allErrors.size(); i++) {
                    errorMessage.append(allErrors.get(i).getDefaultMessage());
                    if (i != allErrors.size() - 1) {
                        errorMessage.append(",");
                    }
                }
                result.setCode(400).setMessage(errorMessage.toString());
                logger.error(errorMessage.toString());
            } else {
                // 3、内部其他错误
                result.setCode(500).setMessage("接口 [" + request.getRequestURI() + "] 内部错误，请联系管理员");
                String message;
                if (handler instanceof HandlerMethod) {
                    HandlerMethod handlerMethod = (HandlerMethod) handler;
                    message = String.format("接口 [%s] 出现异常，方法：%s.%s，异常摘要：%s",
                            request.getRequestURI(),
                            handlerMethod.getBean().getClass().getName(),
                            handlerMethod.getMethod().getName(),
                            e.getMessage());
                } else {
                    message = e.getMessage();
                }
                result.setMessage(message);
                logger.error(message, e);
            }
            responseResult(response, result);
            return new ModelAndView();
        });
    }

    // 处理响应数据格式
    private void responseResult(HttpServletResponse response, Result result) {
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-type", "application/json;charset=UTF-8");
        response.setStatus(200);
        try {
            response.getWriter().write(JSON.toJSONString(result));
        } catch (IOException ex) {
            logger.error(ex.getMessage());
        }
    }

}
